use std::{path::{Path, PathBuf}, sync::Arc};

use api::Router;
use prisma::PrismaClient;
use tokio::fs;
use util::{db, seeder::config_seeder};

use thiserror::Error;

pub mod api;
pub(crate) mod config;
pub(crate) mod opinion;
pub(crate) mod meeting;
pub(crate) mod record;
pub(crate) mod rsync;
pub(crate) mod handle;
pub(crate) mod action;
pub(crate) mod util;
pub(crate) mod prisma;

pub struct Node {

}

#[derive(Error, Debug)]
pub enum NodeError {
	#[error("error opening database as the path contains non-UTF-8 characters")]
	InvalidDatabasePath(PathBuf),
    #[error("An error occurred with the database while applying migrations: {0}")]
	DatabaseError(#[from] prisma_client_rust::QueryError),
}

impl Node {
    pub async fn new(data_dir: impl AsRef<Path>) -> Result<(Arc<PrismaClient>, Arc<Router>), NodeError> {
        let data_dir = data_dir.as_ref();

        #[cfg(debug_assertions)]
		let data_dir = data_dir.join("dev");

        let _ = fs::create_dir_all(&data_dir).await;

        Node::create_folder(&data_dir).await;

        let client = Arc::new(db::load_and_migrate(&format!(
            "file:{}",
            data_dir.join("sqlite.db").as_os_str().to_str().ok_or_else(|| {
                NodeError::InvalidDatabasePath(data_dir.to_path_buf())
            })?
        )).await.unwrap());

        config_seeder(&client).await?;

        let router = api::mount();
        Ok((client, router))
    }

    pub async fn create_folder(data_dir: &Path) {
        for item in vec![
            data_dir.join("tmp"),
            data_dir.join("files"),
            data_dir.join("data"),
            data_dir.join("download"),
            data_dir.join("tpl")
        ] {
            let _ = fs::create_dir_all(item).await;
        }
    }
}
